﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using Spring.Objects.Factory.Config;
using Strongshell.Recoil.Core.Composition.Parsing.DependencyInjection;

namespace Strongshell.Recoil.Core.Composition.Parsing.Handlers
{
    public class MemberInitExpressionHandler : IExpressionHandler
    {
        private readonly IExpressionParser expressionParser;
        private readonly IObjectConfigurationRegistry objectConfigurationRegistry;

        public MemberInitExpressionHandler(IObjectConfigurationRegistry objectConfigurationRegistry, IExpressionParser expressionParser)
        {
            this.expressionParser = expressionParser;
            this.objectConfigurationRegistry = objectConfigurationRegistry;
        }

        public void Handle(IDependencyInjector currentInjector, Expression currentExpression)
        {
            var memberInitExpression = (MemberInitExpression)currentExpression;

            var nestableObjectConfiguration =
                currentInjector.SelectNestableObjectConfiguration(memberInitExpression.NewExpression.Constructor.DeclaringType);

            expressionParser.Parse(new InstantiationDependencyInjector(nestableObjectConfiguration,
                                                                       memberInitExpression.NewExpression.Constructor.
                                                                           DeclaringType),
                                   memberInitExpression.NewExpression);

            foreach (var binding in memberInitExpression.Bindings)
            {
                if (binding.BindingType != MemberBindingType.Assignment)
                {
                    throw new ArgumentException("Only Assignnment member bindings are supported.");
                }

                var assignmentBinding = (MemberAssignment)binding;

                Type memberType = assignmentBinding.Member.MemberType == MemberTypes.Field
                                      ? ((FieldInfo)assignmentBinding.Member).FieldType
                                      : ((PropertyInfo)assignmentBinding.Member).PropertyType;

                expressionParser.Parse(new NestingPropertyDependencyInjector(objectConfigurationRegistry,
                                                                      nestableObjectConfiguration,
                                                                      memberType,
                                                                      assignmentBinding.Member.Name),
                                       assignmentBinding.Expression);
            }
        }
    }
}
